with Ada.Text_IO;  use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Aes;

procedure Vu is
   package M_IO is new Ada.Text_IO.Modular_IO(Aes.Byte);
   
   --Word1, Word2 : Aes.Word;
   Key1,Key2 : Aes.Key;
   Rk: Aes.Key_Schedule;
   Block1,Block2 : Aes.Block;
   Nr: Integer;
   
   Num:Integer;

   procedure Print_Word(Arr: in Aes.Word) is
   begin
      for Index in Arr'Range loop
         M_IO.Put(Arr(Index));
         Put(", ");
      end loop;
      New_Line;
   end;
   
   procedure Print_Block(Arr: in Aes.Block) is
   begin
      for Index in Arr'Range loop
         M_IO.Put(Arr(Index));
         Put(", ");
      end loop;
      New_Line;
   end;
   
   procedure Print_State(Arr: in Aes.State) is
   begin
      for Index in Arr'Range loop
         Print_Word(Arr(Index));
         Put(", ");
      end loop;
      New_Line;
   end;
   
   procedure Print_Key(Arr: in Aes.Key) is
   begin
      for Index in Arr'Range loop
         M_IO.Put(Arr(Index));
         Put (" ,");
      end loop;
      New_Line;
   end;
   
   
   procedure Print_Key_Schedule(Arr: in Aes.Key_Schedule) is
   begin
      for Index in Arr'Range loop
         Print_Word(Arr(Index));
         Put (" ,");
      end loop;
      New_Line;
   end;
   
   
   procedure Init_Word(Arr: out Aes.Word) is 
   begin
      for Index in Arr'Range loop
         Arr(Index):=0;
      end loop;
   end;
   
   
   procedure Init_Block(Arr: out Aes.Block) is 
   begin
      for Index in Arr'Range loop
         Arr(Index):=0;
      end loop;
   end;
   
   
   procedure Init_Key_Schedule(Arr: out Aes.Key_Schedule) is
   begin
      for Index in Arr'Range loop
         Init_Word(Arr(Index));
      end loop;
   end;
   
   procedure Init_Key_Schedule_Cust(Arr: out Aes.Key_Schedule) is
   begin
      for Index in Arr'Range loop
         Arr(Index) := (78,15,93,2);
      end loop;
   end;   
   

begin
   ---
   Put_Line("AES Driver");
   
   ---
   Put("MAXKC = ");
   Put(Aes.MAXKC);
   New_Line;
   
   
   --mul
   Put_Line("AES Mul function");
   M_IO.Put(Aes.Mul(8,3));
   M_IO.Put(Aes.Mul(50,50));
   M_IO.Put(Aes.Mul(8,0));
   M_IO.Put(Aes.Mul(1,2));
   New_Line;
   
   --word_xor
   Put_Line("AES Word_Xor function");
   Print_Word(Aes.Word_Xor((0,1,9,1),(0,0,2,245)));
   Print_Word(Aes.Word_Xor((0,0,99,1),(100,0,2,145)));
   
   --word_xor_xor
   Put_Line("AES Word_Xor_Xor function");
   Print_Word( Aes.Word_Xor_Xor((0,1,0,0),(1,0,1,1),(1,1,1,1)));
   Print_Word( Aes.Word_Xor_Xor((0,1,0,89),(124,0,1,1),(0,1,241,1)));
   New_Line;
   
   Put_Line("AES SubWord");
   Print_Word(Aes.SubWord((1,1,1,255)));
   Print_Word(Aes.SubWord((231,189,0,255)));
   Print_Word(Aes.SubWord((0,0,7,75)));
   New_Line;
   
   
   Put_Line("AES RotWord");
   Print_Word(Aes.RotWord((1,3,4,255)));
   Print_Word(Aes.RotWord((89,0,43,24)));
   Print_Word(Aes.RotWord((41,38,67,8)));
   New_Line;
   
   
   Put_Line("AES Block2State");
   Print_State(Aes.Block2State((
                                1,3,4,255,
                                1,2,3,4,
                                7,8,10,52,
                                0,1,2,15)));
   New_Line;
   
   Put_Line("AES State2Block");
   Print_Block(Aes.State2Block((
                                (1,3,4,255),
                                (1,2,3,4),
                                (7,8,10,52),
                                (0,1,2,15))));
   New_Line;
   
   
   Put_Line("AES SubBytes");
   Print_State(Aes.SubBytes((
                             (1,3,4,255),
                             (1,2,3,4),
                             (7,8,10,52),
                             (0,1,2,15))));
   New_Line;
   
   
   Put_Line("AES InvSubBytes");
   Print_State(Aes.InvSubBytes((
                             (1,3,4,255),
                             (1,2,3,4),
                             (7,8,10,52),
                             (0,1,2,15))));
   New_Line;
   
   
   Print_State(Aes.InvSubBytes((
                             (0,13,89,132),
                             (12,82,10,97),
                             (40,88,42,80),
                             (0,111,102,105))));
   New_Line;
   
   
   
   Put_Line("AES ShiftRows");
   Print_State(Aes.ShiftRows((
                             (1,3,4,255),
                             (1,2,3,4),
                             (7,8,10,52),
                             (0,1,2,15))));
   New_Line;
   
   
   
   Put_Line("AES InvShiftRows");
   Print_State(Aes.InvShiftRows((
                                 (1,3,4,255),
                                 (1,2,3,4),
                                 (7,8,10,52),
                                 (0,1,2,15))));
   New_Line;

   
   Put_Line("AES MixColumns");
   Print_State(Aes.MixColumns((
                               (1,3,4,255),
                               (1,2,3,4),
                               (7,8,10,52),
                               (0,1,2,15))));
   New_Line;
   
   
   Put_Line("AES AddRoundKey");
   Print_State(Aes.AddRoundKey(((1,3,4,255),(1,2,3,4),(7,8,10,52),(0,1,2,15)),
                              (1,3,4,255),
                              (1,3,4,255),
                              (1,3,4,255),
                              (1,3,4,255)
                             ));
   New_Line;
   
   --  --------------------------
   Key1 := (1,3,4,255,1,2,3,4,7,8,10,52,0,1,2,15,
            1,3,4,255,1,2,3,4,7,8,10,52,0,1,2,15);
   Print_Key(Key1);
   
   
   Key2 := (89,32,4,90,1,213,16,4,34,8,80,13,0,1,0,132,
            82,28,76,21,132,48,89,123,90,80,12,12,10,8,40,65);
   
   Print_Key(Key2);
   
   
   
   Put_Line("AES KeySetup4");
   Print_Key_Schedule(Aes.KeySetupEnc4(Key1));
   Print_Key_Schedule(Aes.KeySetupEnc4(Key2));
   
   Put_Line("AES KeySetup6");
   Print_Key_Schedule(Aes.KeySetupEnc6(Key1));
   Print_Key_Schedule(Aes.KeySetupEnc6(Key2));
   
   
   Put_Line("AES KeySetup8");
   Print_Key_Schedule(Aes.KeySetupEnc8(Key1));
   Print_Key_Schedule(Aes.KeySetupEnc8(Key2));
      
   
   Put_Line("AES KeySetupEnc");
   Print_Key_Schedule(Aes.KeySetupEnc(Key1,8)); --4,6, or 8
   Print_Key_Schedule(Aes.KeySetupEnc(Key2,4)); --4,6, or 8
   
   
   -----------
   Put_Line("AES KeyScheduleMod1");
   Print_Key_Schedule(Aes.KeyScheduleMod1(Aes.KeySetupEnc(Key1,4),10)); -- 10, 12, 14
   Print_Key_Schedule(Aes.KeyScheduleMod1(Aes.KeySetupEnc(Key2,6),14)); -- 10, 12, 14
   
   
   Put_Line("AES KeyScheduleMod2");
   Print_Key_Schedule(Aes.KeyScheduleMod1(Aes.KeySetupEnc(Key1,6),14)); -- 10, 12, 14
   Print_Key_Schedule(Aes.KeyScheduleMod1(Aes.KeySetupEnc(Key2,8),12)); -- 10, 12, 14
   
   
   Put_Line("AES KeySetupDec");
   Print_Key_Schedule(Aes.KeySetupDec(Key1,8)); -- 4,6,8
   Print_Key_Schedule(Aes.KeySetupDec(Key2,4)); -- 4,6,8
   
   
   -------
   Put_Line("AES aesKeySetupEnc");
   Aes.AesKeySetupEnc(Rk,  --out key_schedule
                      Key1,--cipherKey
                      192, --keyBits 128,192, 256
                      Nr -- out Integer
                     );
   
   Print_Key_Schedule(Rk);
   Put(Nr);
   New_Line;
   
   Aes.AesKeySetupEnc(Rk,  --out key_schedule
                      Key2,--cipherKey
                      128, --keyBits 128,192, 256
                      Nr -- out Integer
                     );
   
   Print_Key_Schedule(Rk);
   Put(Nr);
   New_Line;
   
   
   -------
   Put_Line("AES aesKeySetupDec");
   Aes.AesKeySetupDec(Rk,  --out key_schedule
                      Key1,--cipherKey
                      192, --keyBits 128,192, 256
                      Nr -- out Integer
                     );
   
   Print_Key_Schedule(Rk);
   Put(Nr);
   New_Line;
   
   Aes.AesKeySetupDec(Rk,  --out key_schedule
                      Key2,--cipherKey
                      256, --keyBits 128,192, 256
                      Nr -- out Integer
                     );
   
   Print_Key_Schedule(Rk);
   Put(Nr);
   New_Line;

   -------
   
   Put_Line("AES AesEncrypt 1");
   Init_Key_Schedule(Rk);
   Nr := 14;

   Block1 := (255,0,0,0, 1,0,0,0, 0,0,0,0, 0,0,0,1);
   Init_Block(Block2);
   Aes.AesEncrypt(Rk,Nr,Block1,Block2);
   Print_Block(Block2);
   New_Line;
   
   
   Put_Line("AES AesDecrypt 1");
      
   Init_Block(Block1);
   Aes.AesDecrypt(Rk,Nr,Block2,Block1);
   Print_Block(Block1);
   New_Line;
   
   
   
   
   Put_Line("AES AesEncrypt 1 - cust");
   Init_Key_Schedule_Cust(Rk);
   Nr := 14;

   Block1 := (255,0,0,0, 1,0,0,0, 0,0,0,0, 0,0,0,1);
   Init_Block(Block2);
   Aes.AesEncrypt(Rk,Nr,Block1,Block2);
   Print_Block(Block2);
   New_Line;
   
   
   Put_Line("AES AesDecrypt 1 - cust");
      
   Init_Block(Block1);
   Aes.AesDecrypt(Rk,Nr,Block2,Block1);
   Print_Block(Block1);
   New_Line;
   
   
   ------------
   
   
   
   
   Put_Line("AES AesEncrypt 2");
   Init_Key_Schedule(Rk);
   Nr := 10;

   Block1 := (255,0,28,0, 1,0,0,0, 0,0,0,92, 5,0,11,7);
   Init_Block(Block2);
   Aes.AesEncrypt(Rk,Nr,Block1,Block2);
   Print_Block(Block2);
   New_Line;
   
   
   Put_Line("AES AesDecrypt 2");
   Init_Block(Block1);
   Aes.AesDecrypt(Rk,Nr,Block2,Block1);
   Print_Block(Block1);
   New_Line;
   
   
   Put_Line("AES AesEncrypt 2 - cust");
   Init_Key_Schedule_Cust(Rk);
   Nr := 10;

   Block1 := (255,0,28,0, 1,0,0,0, 0,0,0,92, 5,0,11,7);
   Init_Block(Block2);
   Aes.AesEncrypt(Rk,Nr,Block1,Block2);
   Print_Block(Block2);
   New_Line;
   
   
   Put_Line("AES AesDecrypt 2 - cust");
   Init_Block(Block1);
   Aes.AesDecrypt(Rk,Nr,Block2,Block1);
   Print_Block(Block1);
   New_Line;   
   
   
   ---------------
   
   
 
   
   Put_Line("AES AesEncrypt 3");
   Init_Key_Schedule(Rk);
   Nr := 10;

   Block1 := (255,0,28,15, 199,0,254,45, 0,89,0,92, 52,130,171,78);
   Init_Block(Block2);
   Aes.AesEncrypt(Rk,Nr,Block1,Block2);
   Print_Block(Block2);
   New_Line;
   
   
   Put_Line("AES AesDecrypt 3");
   Init_Block(Block1);
   Aes.AesDecrypt(Rk,Nr,Block2,Block1);
   Print_Block(Block1);
   New_Line;
   
   
   Put_Line("AES AesEncrypt 3 - cust");
   Init_Key_Schedule_Cust(Rk);
   Nr := 10;

   Block1 := (255,0,28,15, 199,0,254,45, 0,89,0,92, 52,130,171,78);
   Init_Block(Block2);
   Aes.AesEncrypt(Rk,Nr,Block1,Block2);
   Print_Block(Block2);
   New_Line;
   
   
   Put_Line("AES AesDecrypt 3 - cust");
   Init_Block(Block1);
   Aes.AesDecrypt(Rk,Nr,Block2,Block1);
   Print_Block(Block1);
   New_Line;     
   
   
   
   --  Put_Line("Gimme a number in decimal, octal, or hex:");
   --  Get(Num);
   --  Put_Line("Decimal value: " & Integer'Image(Num));
   --  Put("Octal Value: ");
   --  Put(Item => Num, Base => 8);
   --  New_Line;
   --  Put("Hexadecimal Value: ");
   --  Put(Item => Num, Base => 16);
   --  New_Line(2);
   --  ------
   --  Put_Line("Enter a file permission in octal: ");
   --  Get(Num);
   --  Put_Line("Decimal Value:" & Integer'Image(Num));
   
exception 
	when constraint_error =>
		put_line("some exception occured");
end vu; -- procedure name is optional at end;

